package com.gadgets.cm05.statistic;

import com.gadgets.cm05.common.constant.Cm05Constant;
import com.gadgets.cm05.common.dto.MathList;
import com.gadgets.framework.common.exception.GadgetsValidateException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.math3.util.FastMath;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 功能说明：中心极限定理转换器
 * 著作者：修峻青
 * 创建日期：2023-01-07
 */
public class CLTUtils {

    /**
     * 中心极限定理计算
     * (基础公式)
     * @param avg   样本均值
     * @param avg0  目标均值
     * @param s     样本方差
     * @param n     样本总数
     * @return      中心极限值
     */
    public static BigDecimal getClt(BigDecimal avg, BigDecimal avg0, BigDecimal s, BigDecimal n){
        if(null==avg){
            throw new GadgetsValidateException("样本均值不能为空");
        }
        if(null==avg0){
            throw new GadgetsValidateException("总体均值不能为空");
        }
        if(null==s){
            throw new GadgetsValidateException("方差不能为空");
        }
        if(null==n){
            throw new GadgetsValidateException("样本数量不能为空");
        }
        return avg.subtract(avg0).divide(
                s.divide(
                        new BigDecimal(FastMath.sqrt(n.doubleValue())), RoundingMode.HALF_UP
                )
                , RoundingMode.HALF_UP
        );
    }

    /**
     * 中心极限定理计算
     * (样本入参-算术平均)
     * @param itemList  样本值
     * @param avg0      目标均值
     * @param avgType   平均值类型 {@link Cm05Constant.AVG_TYPE}
     * @return          中心极限值
     */
    public static BigDecimal getClt(MathList<BigDecimal> itemList, BigDecimal avg0, String avgType){
        if(CollectionUtils.isEmpty(itemList)){
            throw new GadgetsValidateException("样本不能为空");
        }
        BigDecimal avg = null;
        if(avgType.equals(Cm05Constant.AVG_TYPE.MEAN)) {
            avg = AvgUtils.mean(itemList);
        }else if(avgType.equals(Cm05Constant.AVG_TYPE.GERO_MEAN)){
            avg = AvgUtils.geometricMean(itemList);
        }
        BigDecimal devision = VarianceUtils.devisionForItem(itemList);
        return getClt(avg, avg0, devision, new BigDecimal(itemList.size()));
    }



}
